package yxy.apple.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.zip.DataFormatException;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.InflaterInputStream;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ByteUtility {
	/**
	 * 4字节一组，8组一行，小写样式
	 * 
	 * @param bytes
	 * @return
	 */
	public static String toHexString(byte[] bytes) {
		return toHexString(bytes, 4, 8, false);
	}

	/**
	 * 
	 * @param bytes     需要处理的字节数组
	 * @param block     几个字节为一块
	 * @param group     几个块为一组（行）
	 * @param uppercase 是否大写显示
	 * @return
	 */
	public static String toHexString(byte[] bytes, int block, int group, boolean uppercase) {
		StringBuffer buffer = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			if (block > 0 && i > 0) {
				if (group > 0 && i % (block * group) == 0) {
					buffer.append("\r\n");
				} else if (i % block == 0) {
					buffer.append(" ");
				}
			}

			String value = Integer.toHexString(0x000000FF & bytes[i]);
			if (value.length() == 1) {
				buffer.append("0");
			}
			buffer.append(value);
		}
		String result = buffer.toString();
		if (uppercase) {
			return result.toUpperCase();
		} else {
			return result.toLowerCase();
		}
	}

	public static byte[] hexStringToBytes(String hex) {
		if (hex != null) {
			if (hex.trim().length() >= 2) {
				int length = hex.length() / 2;
				byte[] result = new byte[length];
				for (int i = 0; i < length; i++) {
					String code = hex.substring(i * 2, i * 2 + 2);
					byte b = (byte) Integer.parseInt(code, 16);
					// byte b = Byte.parseByte(code, 16);
					result[i] = b;
				}
				return result;
			} else {
				return new byte[0];
			}
		} else {
			return null;
		}
	}

	public static byte[] zip(byte[] data) throws DataFormatException {
		try {
			return deflate(data, ZipOutputStream.class);
		} catch (Exception e) {
			throw new DataFormatException(e.getMessage());
		}
	}

	public static byte[] gzip(byte[] data) throws DataFormatException {
		try {
			return deflate(data, GZIPOutputStream.class);
		} catch (Exception e) {
			throw new DataFormatException(e.getMessage());
		}
	}

	private static byte[] deflate(byte[] data, Class<?> cls) throws IOException, InstantiationException, IllegalAccessException, IllegalArgumentException,
			InvocationTargetException, NoSuchMethodException, SecurityException {
		ByteArrayOutputStream bao = new ByteArrayOutputStream();
		DeflaterOutputStream dos = (DeflaterOutputStream) cls.getConstructor(OutputStream.class).newInstance(bao);
		dos.write(data);
		dos.finish();
		dos.flush();
		byte[] result = bao.toByteArray();
		dos.close();
		return result;
	}

	public static byte[] unzip(byte[] data) throws DataFormatException {
		try {
			return inflate(data, ZipInputStream.class);
		} catch (Exception e) {
			throw new DataFormatException(e.getMessage());
		}
	}

	public static byte[] ungzip(byte[] data) throws DataFormatException {
		try {
			return inflate(data, GZIPInputStream.class);
		} catch (Exception e) {
			throw new DataFormatException(e.getMessage());
		}
	}

	private static byte[] inflate(byte[] data, Class<?> cls) throws IOException, InstantiationException, IllegalAccessException, IllegalArgumentException,
			InvocationTargetException, NoSuchMethodException, SecurityException {
		ByteArrayInputStream bis = new ByteArrayInputStream(data);
		ByteArrayOutputStream bao = new ByteArrayOutputStream();
		InflaterInputStream iis = (InflaterInputStream) cls.getConstructor(InputStream.class).newInstance(bis);

		byte[] buffer = new byte[32768];
		int length = iis.read(buffer);
		while (length != -1) {
			bao.write(buffer, 0, length);
			length = iis.read(buffer);
		}
		iis.close();
		bao.close();
		return bao.toByteArray();
	}

	public static byte[] align(byte[] data, int block) {
		int length = data.length;
		if (length > 0) {
			int group = (length - 1) / block + 1;
			int size = group * block;
			byte[] buffer = new byte[size];
			System.arraycopy(data, 0, buffer, 0, data.length);
			return buffer;
		} else {
			return data;
		}
	}

	public static boolean equals(byte[] one, byte[] another) {
		boolean result = true;
		if (one == null || another == null) {
			result = false;
		} else if (one.length != another.length) {
			result = false;
		} else {
			for (int i = 0; i < one.length; i++) {
				if (one[i] != another[i]) {
					result = false;
					break;
				}
			}
		}
		return result;
	}

	public static byte[] join(byte[] one, byte[] another) {
		byte[] result = new byte[one.length + another.length];
		System.arraycopy(one, 0, result, 0, one.length);
		System.arraycopy(another, 0, result, one.length, another.length);
		return result;
	}

	public static byte[] copy(byte[] data) {
		if (data != null) {
			byte[] buffer = new byte[data.length];
			System.arraycopy(data, 0, buffer, 0, data.length);
			return buffer;
		} else {
			return null;
		}
	}
}
